import { createVNode, render } from "vue";
import { ElTooltip } from "element-plus";

/** 检测元素是否溢出 */
const checkOverflow = el => el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth;

/**
 * 应用多行截断样式（-webkit-line-clamp）
 * @param {HTMLElement} el
 * @param {number} lines
 */
const applyClampStyles = (el, lines) => {
  el.style.display = "-webkit-box";
  el.style.setProperty("-webkit-box-orient", "vertical");
  el.style.setProperty("-webkit-line-clamp", String(lines));
  el.style.overflow = "hidden";
  el.style.whiteSpace = "normal";
  el.style.wordBreak = "break-word";
  el.style.lineHeight = el.style.lineHeight || "1.4em";
  el.style.maxHeight = `calc(${el.style.lineHeight} * ${lines})`;
};

/** 单例挂载容器（程序化渲染 Tooltip） */
let singletonContainer = null;
function ensureContainer() {
  if (!singletonContainer) {
    singletonContainer = document.createElement("div");
    singletonContainer.setAttribute("data-el-clamp-tooltip", "1");
    document.body.appendChild(singletonContainer);
  }
  return singletonContainer;
}

/**
 * 程序化渲染并显示 Tooltip
 * - text: tooltip 内容（如果 tooltipProps 中自带 content，以 tooltipProps.content 为准）
 * - virtualRef: 定位参考
 * - tooltipProps: 用户传入的 ElTooltip props（会与内部必要 props 合并）
 */
function showTooltip(text, virtualRef, tooltipProps) {
  const container = ensureContainer();
  // 默认 props（可被 tooltipProps 覆盖）
  const defaultProps = {
    content: text,
    teleported: true,
    virtualRef,
    virtualTriggering: true,
    placement: "top",
    popperOptions: {
      modifiers: [{ name: "offset", options: { offset: [0, 8] } }],
    },
    modelValue: true,
    visible: true,
  };
  // 合并：用户传入的 tooltipProps 优先（覆盖默认）
  const merged = Object.assign({}, defaultProps, tooltipProps || {});
  // 如果没有在 tooltipProps 中指定 content，则使用 text
  if (!("content" in merged) && !("raw-content" in merged) && !("rawContent" in merged)) {
    merged.content = text;
  }
  // 强制将 virtualRef 与 virtualTriggering 应用，除非用户显式设置为 false
  if (!("virtualRef" in (tooltipProps || {}))) merged.virtualRef = virtualRef;
  if (!("virtualTriggering" in (tooltipProps || {}))) merged.virtualTriggering = true;

  const vnode = createVNode(ElTooltip, merged);
  render(vnode, container);
}

/** 隐藏 Tooltip */
function hideTooltip() {
  if (!singletonContainer) return;
  render(null, singletonContainer);
}

/** 创建测量 handler（只负责设置 el.__clamp_tooltip_isOverflow 标记） */
const createOverflowHandler = el => {
  return () => {
    window.requestAnimationFrame(() => {
      const isOverflow = checkOverflow(el);
      el.__clamp_tooltip_isOverflow = !!isOverflow;
    });
  };
};

/**
 * v-clamp-tooltip 指令
 *
 * 支持的绑定值（binding.value）：
 * - number -> 代表行数（例如 v-clamp-tooltip="2"）
 * - object -> { lines?: number, tooltipProps?: Record<string, any> }
 *     示例：
 *     v-clamp-tooltip="{ lines: 3, tooltipProps: { placement: 'bottom', popperClass: 'my-class' } }"
 */
export const clampTooltip = {
  mounted(el, binding) {
    // 解析 binding：支持 number 或 object
    let lines = 2;
    let tooltipProps = undefined;

    if (binding.value == null) {
      lines = 2;
    } else if (typeof binding.value === "number" || typeof binding.value === "string") {
      // 传入数字或字符串数字 -> 行数
      lines = Number(binding.value) || 2;
    } else if (typeof binding.value === "object") {
      const v = binding.value;
      if (v.lines != null) lines = Number(v.lines) || 2;
      if (v.tooltipProps && typeof v.tooltipProps === "object") {
        tooltipProps = v.tooltipProps;
      }
    }

    // 应用截断样式
    applyClampStyles(el, lines);

    // 创建并保存 handler：用于测量是否溢出（只维护状态）
    const handler = createOverflowHandler(el);
    el.__clamp_tooltip_handler = handler;
    requestAnimationFrame(handler);

    // 监听窗口 resize：尺寸变化时重新测量
    window.addEventListener("resize", handler, { passive: true });

    // 鼠标进入时显示（仅当溢出且文本非空）
    const onEnter = () => {
      handler();
      const isOverflow = !!el.__clamp_tooltip_isOverflow;
      const text = el.textContent?.trim() ?? "";
      if (isOverflow && text) {
        const virtualRef = {
          getBoundingClientRect: () => el.getBoundingClientRect(),
        };
        showTooltip(text, virtualRef, tooltipProps);
      }
    };

    // 鼠标离开 / blur 隐藏
    const onLeave = () => {
      hideTooltip();
    };

    // 键盘 focus 支持
    const onFocus = e => onEnter(e);
    const onBlur = () => onLeave();

    el.addEventListener("mouseenter", onEnter);
    el.addEventListener("mouseleave", onLeave);
    el.addEventListener("focus", onFocus);
    el.addEventListener("blur", onBlur);

    // 保存 listeners & config 以便 updated/unmounted 使用
    el.__clamp_tooltip_listeners = {
      onEnter,
      onLeave,
      onFocus,
      onBlur,
    };
    el.__clamp_tooltip_config = { lines, tooltipProps };
  },

  updated(el, binding) {
    // 若用户在 runtime 更新了指令的 binding（例如修改了 tooltipProps 或 lines），要更新内部配置
    // 先触发一次测量
    const handler = el.__clamp_tooltip_handler;
    if (typeof handler === "function") {
      requestAnimationFrame(handler);
    }

    // 更新 config（支持绑定值改变时动态更新 lines / tooltipProps）
    const prev = el.__clamp_tooltip_config || {};
    let lines = prev.lines || 2;
    let tooltipProps = prev.tooltipProps;

    if (binding.value == null) {
      lines = prev.lines || 2;
    } else if (typeof binding.value === "number" || typeof binding.value === "string") {
      lines = Number(binding.value) || 2;
    } else if (typeof binding.value === "object") {
      const v = binding.value;
      if (v.lines != null) lines = Number(v.lines) || 2;
      if (v.tooltipProps && typeof v.tooltipProps === "object") tooltipProps = v.tooltipProps;
    }

    // 重新应用样式（如果行数变了）
    applyClampStyles(el, lines);
    el.__clamp_tooltip_config = { lines, tooltipProps };
  },

  unmounted(el) {
    // 清理 resize handler 引用
    const handler = el.__clamp_tooltip_handler;
    if (typeof handler === "function") {
      window.removeEventListener("resize", handler);
      delete el.__clamp_tooltip_handler;
    }

    // 移除注册的鼠标/焦点事件
    const listeners = el.__clamp_tooltip_listeners;
    if (listeners) {
      el.removeEventListener("mouseenter", listeners.onEnter);
      el.removeEventListener("mouseleave", listeners.onLeave);
      el.removeEventListener("focus", listeners.onFocus);
      el.removeEventListener("blur", listeners.onBlur);
      delete el.__clamp_tooltip_listeners;
    }

    // 清理 config
    delete el.__clamp_tooltip_config;
    hideTooltip();
  },
};

export default clampTooltip;
